/*
 * Copyright (c) 2009 by unreserved.org.
 * All rights reserved.
 */

package org.unreserved.ladderplot;

import java.io.*;

/**
 * Represents one line of output.
 * 
 * <p>Allows lines to grow dynamically.
 */
public class TextLine {
    protected char[] line;
    protected int length;
    protected int maxLength;
    
    /**
     * Creates new TextLine.
     * 
     * @param size number of chars initially allocated for the line
     * @param maxLength max line length, -1 means no limit
     */
    public TextLine(int size, int maxLength) {
        this.line = new char[size];
        this.length = 0;
        this.maxLength = maxLength;
    }
    
    /**
     * Write the specified string into this line starting at the
     * specified offset. This may involve growing the underlying
     * character array. The string will be truncated if the offset is
     * negative or if it would go beyond the end of a limited-length
     * TextLine.
     * 
     * @param s string to write
     * @param destPos start index in line; may be negative
     */
    public void write(String s, int destBegin) {
        int srcBegin; // index of first character in s to copy
        int srcEnd;   // index after last character in s to copy
        int n;        // number of characters to copy
        
        if (destBegin >= 0) {
            srcBegin = 0;
        } else {
            srcBegin = -destBegin;
            destBegin = 0;
        }
        
        n = s.length() - srcBegin;
        
        if (destBegin + n > line.length) {
            // extend line and/or truncate input string
            int newLineLength = destBegin + n;
            if (maxLength > -1 && newLineLength > maxLength) {
                newLineLength = maxLength;
                n = newLineLength - destBegin;
            }
            if (newLineLength > line.length) {
                // line was extended - create new char[]
                char[] newLine = new char[newLineLength];
                System.arraycopy(line, 0, newLine, 0, length);
                line = newLine;
            }
        }
        srcEnd = srcBegin + n;
        
        if (srcEnd > srcBegin) {
            // fill up with space characters
            while (length < destBegin) {
                line[length++] = ' ';
            }
            s.getChars(srcBegin, srcEnd, line, destBegin);
            if (destBegin + n > length) {
                length = destBegin + n;
            }
        }
    }
    
    /**
     * Writes this line to the specified Writer.
     */
    public void write(Writer out) throws IOException {
        out.write(line, 0, length);
    }
    
    public String toString() {
        return new String(line, 0, length);
    }
    
    
    ///////////////////////////////////////////////////////////////////////
    // unit testing
    
    /*
    private static int[][] lineSpec = {
        { 10, 10 },
        { 10, 20 },
        { 10, -1 }
    };
    private static String s = "12345";
    
    private static int[] destBegin = {
        -10, -2, 0, 3,
        8, 12,
        18, 22
    };
    
    private static String[][] expectedResults = {
        // expected results when s added to line1
        { "", "345", "12345", "   12345",
          "        12", "",
          "", ""
        },
        // expected results when s added to line2
        { "", "345", "12345", "   12345",
          "        12345", "            12345",
          "                  12", ""
        },
        // expected results when s added to line3
        { "", "345", "12345", "   12345",
          "        12345", "            12345",
          "                  12345", "                      12345"
        },
    };
    
    public static void main(String[] args) {
        for (int i = 0; i < lineSpec.length; i++) {
            for (int j = 0; j < destBegin.length; j++) {
                try {
                    TextLine line = new TextLine(lineSpec[i][0], lineSpec[i][1]);
                    line.write(s, destBegin[j]);
                    String result = line.toString();
                    if (result.equals(expectedResults[i][j])) {
                        System.out.println("Test i+" + i + ",j=" + j +
                                           ": OK, result=\"" + result + "\"");
                    } else {
                        System.err.println("Test i=" + i + ", j=" + j +
                                           " FAIL, result=\"" + result +
                                           "\", expectedResult=\"" + expectedResults[i][j] + "\"");
                    }
                } catch (RuntimeException ex) {
                    System.out.println("i=" + i + ", j=" + j);
                    throw ex;
                }
            }
        }
    }
    */
}
